﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleCsv
{
    public class CsvRow : List<String>
    {
        public int CurrentIndex { get; private set; }

        public CsvRow(IEnumerable<String> collection = null)
        {
            if (collection != null) { AddRange(collection); }
            CurrentIndex = 0;
        }

        // Support for collection initializer
        public void Add(object o)
        {
            base.Add(o == null ? "" : o.ToString());
        }

        public bool IsEmpty
        {
            get
            {
                return Count == 0 || Count == 1 && String.IsNullOrEmpty(this[0]);
            }
        }

        /// <summary>
        /// Next element.
        /// </summary>
        /// <returns></returns>
        public String Next()
        {
            return this[CurrentIndex++];
        }

        public String NextOrDefault(String defaultValue = null)
        {
            if (CurrentIndex < 0 || CurrentIndex >= base.Count) { return defaultValue; }
            return this[CurrentIndex++];
        }

        // Throws an IndexOutOfRangeException if index not present, FormatException if parse fails
        /// <summary>
        /// Parse the CSV field using static Parse() or Parse(IFormatProvider) method on the type.
        /// Supports nullable types and lists.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="index"></param>
        /// <param name="provider"></param>
        /// <throws>IndexOutOfRange exception if index not present, FormatException if parse fails</throws>
        /// <returns></returns>
        public T Parse<T>(int index, IFormatProvider formatProvider = null)
        {
            var s = this[index];
            return (T)ParseHelper.Parse(s, typeof(T), formatProvider);        
        }

        /// <summary>
        /// Parse the CSV field. 
        /// In case of error, returns the default value. Throws no exceptions.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="index"></param>
        /// <param name="defaultValue"></param>
        /// <param name="provider"></param>
        /// <returns></returns>
        public T ParseOrDefault<T>(int index, T defaultValue = default(T), IFormatProvider provider = null)
        {
            try
            {
                return Parse<T>(index);
            }
            catch (Exception)
            {
                return defaultValue;
            }
        }

        /// <summary>
        /// Parse the next CSV field. 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="formatProvider"></param>
        /// <returns></returns>
        public T ParseNext<T>(IFormatProvider formatProvider = null)
        {
            var s = Next();
            return (T)ParseHelper.Parse(s, typeof(T), formatProvider);
        }

        /// <summary>
        /// Parse the next CSV field. 
        /// In case of error, returns the default value. Throws no exceptions.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="defaultValue"></param>
        /// <param name="formatProvider"></param>
        /// <returns></returns>
        public T ParseNextOrDefault<T>(T defaultValue = default(T), IFormatProvider formatProvider = null)
        {
            try
            {
                return ParseNext<T>(formatProvider);
            }
            catch (Exception)
            {
                return defaultValue;
            }
        }

        /// <summary>
        /// Parse a list from the field
        /// </summary>
        /// <typeparam name="ListT"></typeparam>
        /// <param name="index"></param>
        /// <param name="delimiterChar"></param>
        /// <param name="quoteChar"></param>
        /// <returns></returns>
        public ListT ParseList<ListT>(int index, char delimiterChar = ';', char quoteChar = '\'')
            where ListT: System.Collections.IList, new()
        {
            var s = this[index];
            return (ListT)ParseHelper.ParseList(s, typeof(ListT), delimiterChar, quoteChar);
        }

        /// <summary>
        /// Parse the next list from the field
        /// </summary>
        /// <typeparam name="ListT"></typeparam>
        /// <param name="delimiterChar"></param>
        /// <param name="quoteChar"></param>
        /// <returns></returns>
        public ListT ParseNextList<ListT>(char delimiterChar = ';', char quoteChar = '\'')
            where ListT: System.Collections.IList, new()
        {
            var s = Next();
            return (ListT)ParseHelper.ParseList(s, typeof(ListT), delimiterChar, quoteChar);
        }

    }
}
